package com.example.shirodemo.config;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.shiro.mgt.SecurityManager;
@Configuration
public class ShiroConfig{
    //设置url过滤规则
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    //shirFilter
   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
   shiroFilterFactoryBean.setSecurityManager(securityManager);
    //拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    // 配置不需要权限的资源
     filterChainDefinitionMap.put("/static/**", "anon");
     filterChainDefinitionMap.put("/index","anon");
    //配置退出过滤器,退出代码Shiro已经替我们实现
      filterChainDefinitionMap.put("/logout", "logout");
    //过滤链定义，从上向下顺序执行，/**放在最下边;
     //<!-- authc:所有url都必须认证通过才可以访问;
        filterChainDefinitionMap.put("/**", "authc");
     // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
     // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
    //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
         return shiroFilterFactoryBean;
  }
      /**
      * 凭证匹配器
      * 密码校验交给Shiro的SimpleAuthenticationInfo进行处
  理
      *
      * @return
      */
      @Bean
       public HashedCredentialsMatcher hashedCredentialsMatcher() {
          HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5"
        );//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);
        //散列 的次数，md5(md5(""));
          return hashedCredentialsMatcher;
 }
     //设置在身份验证尝试期间使用的凭证匹配器
       @Bean
        public ShiroRealm myShiroRealm() {
        ShiroRealm myShiroRealm = new ShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
         return myShiroRealm;
  }
      //安全管理器 shiro的核心，管理用户信息以及安全数据
        @Bean(name = "securityManager")
        public SessionsSecurityManager securityManager()
      {
          DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
          securityManager.setRealm(myShiroRealm());
            return securityManager;
      }
       /**
      * 开启Shiro的注解(如
  @RequiresRoles,@RequiresPermissions),需借助SpringAOP扫
  描使用Shiro注解的类,并在必要时进行安全逻辑验证
      * 配置以下两个bean(DefaultAdvisorAutoProxyCreator
  和AuthorizationAttributeSourceAdvisor)即可实现此功能
      * @return
      */@Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
         DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
         advisorAutoProxyCreator.setProxyTargetClass(true);
       return advisorAutoProxyCreator;
  }
      /**
      * 开启shiro aop注解支持.
      * 使用代理方式;需要开启代码支持;
      *
      * @param securityManager
      * @return
      */
      @Bean
       public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
      AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
 }
      @Bean(name = "simpleMappingExceptionResolver")
      public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
       SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");
        //数据库异常处理
        mappings.setProperty("UnauthorizedException", "403");
           r.setExceptionMappings(mappings);
           r.setDefaultErrorView("error");
           r.setExceptionAttribute("ex");
           return r;
   }
}